/**
 * Cell class. A Cell is one element in a Grid. A Cell knows which Ship is
 * occupying it. Cell is responsible for handling attacks. As well as this, Cell
 * can calculate what the UI should display.
 */
public class Cell {
	/*
	 * Constants 
	 */
	// Attack constants - used by Cell.tryAttack
	public static final int ATTACK_ALREADY = 1001;
	public static final int ATTACK_HIT = 1002;
	public static final int ATTACK_MISS = 1003;
	public static final int ATTACK_SUNK = 1004;

	// Display constants - used by Cell.displayState
	public static final int DISPLAY_BLANK = 2001;
	public static final int DISPLAY_HIT = 2002;
	public static final int DISPLAY_MISS = 2003;
	public static final int DISPLAY_OCCUPIED = 2004;

	private int x;
	private int y;
	private Ship occupyingShip;
	private Player owningPlayer;
	private boolean attacked;

	/**
	 * Cell constructor. Puts the cell in the initial state of unoccupied,
	 * unattacked and not hit. Also sets its x and y coordinates, and who the
	 * cell belongs to.
	 * 
	 * @param owningPlayer
	 *            The player who this cell belongs to.
	 * @param x
	 *            The x-coordinate for this cell. Will always be in the range 0
	 *            to Game.GRID_SIZE-1, inclusive.
	 * @param y
	 *            The y-coordinate for this cell. Will always be in the range 0
	 *            to Game.GRID_SIZE-1, inclusive.
	 */
	public Cell(Player owningPlayer, int x, int y) {
		this.attacked = false;
		this.owningPlayer = owningPlayer;
		this.x = x;
		this.y = y;
	}

	/**
	 * Calculates what the user interface should display for this particular
	 * cell. The result should be one of the following four values, depending on
	 * the state of the cell:
	 * 
	 * Cell.DISPLAY_HIT - returned if this cell has been attacked, and the
	 * attack hit.
	 * 
	 * Cell.DISPLAY_MISS - returned if this cell has been attacked, but the
	 * attack missed.
	 * 
	 * Cell.DISPLAY_OCCUPIED - returned if two conditions are met: (a) This cell
	 * is occupied by a ship but has not been attacked. (b) The specified
	 * viewingPlayer is allowed to see which cells are occupied on this grid.
	 * They are allowed when either: the static field UI.isCheating is true, or,
	 * when the player who is viewing this cell is also the one who this cell
	 * belongs to.
	 * 
	 * Cell.DISPLAY_BLANK - returned in all other cases.
	 * 
	 * @param viewingPlayer
	 *            The player that is viewing this grid.
	 * @return Returns the display state - one of Cell.DISPLAY_BLANK,
	 *         Cell.DISPLAY_HIT, Cell.DISPLAY_MISS or Cell.DISPLAY_OCCUPIED -
	 *         see above.
	 */
	public int displayState(Player viewingPlayer) {
		if (isHit()) {
			return Cell.DISPLAY_HIT;
		} else if (attacked) {
			return Cell.DISPLAY_MISS;
		} else if (occupyingShip != null) {
			if (UI.isCheating || (owningPlayer == viewingPlayer))
				return Cell.DISPLAY_OCCUPIED;
		}
		return Cell.DISPLAY_BLANK;
	}

	/** @return The player who this cell belongs to. */
	public Player getPlayer() {
		return this.owningPlayer;
	}

	/** @return The ship that occupies this cell. */
	public Ship getOccupyingShip() {
		return this.occupyingShip;
	}

	/** @return The x-coordinate of this cell. */
	public int getX() {
		return this.x;
	}

	/** @return The y-coordinate of this cell. */
	public int getY() {
		return this.y;
	}

	/**
	 * Hit cell 
	 * 
	 * @return Returns true if this cell was hit, false otherwise.
	 */
	public boolean isHit() {
		return (getOccupyingShip() != null) && wasAttacked();
	}

	/**
	 * Marks this cell as occupied by the specified ship.
	 * 
	 * @param ship
	 *            The ship to occupy this cell with.
	 */
	public void occupyWith(Ship ship) {
		this.occupyingShip = ship;
	}

	/**
	 * Attempts an attack on this cell. If this cell has been attacked before,
	 * this method should just return Cell.ATTACK_ALREADY and do nothing else.
	 * Otherwise, this method must:
	 * 
	 * 1. Mark this cell as attacked.
	 * 
	 * 2. Register one hit to the occupying ship, if there is a ship occupying
	 * this cell.
	 * 
	 * 3. Return either Cell.ATTACK_HIT, Cell.ATTACK_MISS or Cell.ATTACK_SUNK
	 * depending on the outcome of the attack. See the explanations of each
	 * value below.
	 * 
	 * @return Returns one of the following Cell conditions per the above four values
	 */
	public int tryAttack() {
		if (wasAttacked())
			return Cell.ATTACK_ALREADY;

		attacked = true;

		if (occupyingShip != null) {
			occupyingShip.hit();
			if (occupyingShip.isSunk()) {
				return Cell.ATTACK_SUNK;
			} else {
				return Cell.ATTACK_HIT;
			}
		}

		return Cell.ATTACK_MISS;
	}

	/**
	 * Has this cell been attacked before
	 * 
	 * @return Returns true if this cell has been attacked before, false
	 *         otherwise.
	 */
	public boolean wasAttacked() {
		return attacked;
	}

}
